package org.example.memora.configur;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.StrUtil;
import lombok.extern.slf4j.Slf4j;
import org.checkerframework.checker.units.qual.A;
import org.example.memora.DTO.UserRedisDTO;
import org.example.memora.common.utils.StompPrincipal;
import org.example.memora.interceptor.WebSocketHandshakeInterceptor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.messaging.Message;
import org.springframework.messaging.MessageChannel;
import org.springframework.messaging.simp.config.ChannelRegistration;
import org.springframework.messaging.simp.config.MessageBrokerRegistry;
import org.springframework.messaging.simp.stomp.StompCommand;
import org.springframework.messaging.simp.stomp.StompHeaderAccessor;
import org.springframework.messaging.support.ChannelInterceptor;
import org.springframework.web.socket.config.annotation.EnableWebSocketMessageBroker;
import org.springframework.web.socket.config.annotation.StompEndpointRegistry;
import org.springframework.web.socket.config.annotation.WebSocketMessageBrokerConfigurer;
import org.springframework.web.socket.config.annotation.WebSocketTransportRegistration;

import java.util.Map;

import static org.example.memora.common.constant.RedisConstants.LOGIN_USER_KEY;

@Slf4j
@Configuration
@EnableWebSocketMessageBroker
public class WebSocketConfig implements WebSocketMessageBrokerConfigurer {
    @Autowired
    private StringRedisTemplate stringRedisTemplate;
    @Override
    public void configureClientOutboundChannel(ChannelRegistration registration) {
        registration.taskExecutor()
                .corePoolSize(32)
                .maxPoolSize(100)
                .queueCapacity(800);
    }

    @Override
    public void configureWebSocketTransport(WebSocketTransportRegistration registration) {
        // 设置为 30 秒
        registration.setSendTimeLimit(30000);
        // 可选：增加缓冲区大小（512KB）
        registration.setSendBufferSizeLimit(1024 * 1024);
    }

    @Override
    public void configureMessageBroker(MessageBrokerRegistry registry) {
        // 启用简单内存消息代理，前端订阅路径前缀为 /topic
        // 支持群聊 + 私聊
        registry.enableSimpleBroker("/topic", "/user");
        // 应用前缀，客户端发送消息用 /app 开头
        registry.setApplicationDestinationPrefixes("/app");
    }

    @Override
    public void registerStompEndpoints(StompEndpointRegistry registry) {
        registry.addEndpoint("/ws-chat/websocket")
                .addInterceptors(new WebSocketHandshakeInterceptor())
                .setAllowedOriginPatterns("*");

        // 注册 WebSocket 端点，允许跨域，支持SockJS回退
        registry.addEndpoint("/ws-chat")
                .addInterceptors(new WebSocketHandshakeInterceptor())
                // 添加自定义拦截器
                .setAllowedOriginPatterns("*")
                .withSockJS();
    }
    @Override
    public void configureClientInboundChannel(ChannelRegistration registration) {
        registration.interceptors(new ChannelInterceptor() {
            @Override
            public Message<?> preSend(Message<?> message, MessageChannel channel) {
                StompHeaderAccessor accessor = StompHeaderAccessor.wrap(message);
                //log.info("preSend 被调用，command = {}", accessor.getCommand());
                if (StompCommand.CONNECT.equals(accessor.getCommand())) {
                    String tokenHeader = accessor.getFirstNativeHeader("Authorization");
                    //log.info("WebSocket CONNECT 请求，Authorization = {}", token);

                    if (StrUtil.isBlank(tokenHeader)) {
                        //log.info("WebSocket CONNECT 缺失 token，拒绝绑定用户身份");
                        return null;
                    }
                    if (StrUtil.isBlank(tokenHeader) || !tokenHeader.startsWith("Bearer ")) {
                        // 无效请求，直接放行（或按需拦截）
                        return null;
                    }
// 移除 "Bearer " 前缀，保留 token
                    String token = tokenHeader.substring(7);

                    String key = LOGIN_USER_KEY + token;
                    Map<Object, Object> userMap = stringRedisTemplate.opsForHash().entries(key);
                    if (userMap.isEmpty()) {
                        //log.info("WebSocket CONNECT token 无效，Redis 未找到用户信息: {}", key);
                        return null;
                    }

                    UserRedisDTO userDTO = BeanUtil.fillBeanWithMap(userMap, new UserRedisDTO(), false);
                    if (userDTO.getUserId() == null) {
                        //log.info("WebSocket CONNECT userDTO 无效: {}", userDTO);
                        return null;
                    }

                    Long userId = userDTO.getUserId();
                    accessor.setUser(new StompPrincipal(userId));
                    //log.info("WebSocket 用户身份绑定成功 userId = {}", userId);
                }

                return message;
            }
        });
    }

}

